//
// SVN Notifier
// Copyright 2007 SIA Computer Hardware Design (www.chd.lv)
//
// This file is part of SVN Notifier.
//
// SVN Notifier is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// SVN Notifier is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>
//

using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using System.Threading;
using System.Timers;
using System.Windows.Forms;
using IconEx;
using DragNDrop;


namespace CHD.SVN_Notifier
{
	public class MainForm : Form
	{
		#region Windows Forms Designer variables

		private IContainer components = null;
		private ContextMenu trayContextMenu;
		private Button btnUpdate;
		private Button btnChangeLog;
		private MenuItem menuItem_ShowList;
		private MenuItem menuItem3;
		private MenuItem menuItem_UpdateAll;
		private MenuItem menuItem2;
		private MenuItem menuItem_Exit;
		private ImageList imageListFolderStatus;
		private FolderBrowserDialog folderBrowserDialog;
		private System.Timers.Timer statusUpdateTimer;
		private MainMenu mainMenu;
		private MenuItem menuItemFile;
		private MenuItem menuItemHelp;
		private MenuItem menuItemSettings;
		private MenuItem menuItemExit;
		private MenuItem menuItemAbout;
		private MenuItem menuItem1;
		private MenuItem menuItemUpdateAll;
		private Button btnOpenFolder;
		private Button btnLog;
		private MenuItem menuItemAddFolder;
		private MenuItem menuItemDelete;
		private Button btnCommit;
		private ContextMenu contextMenu;
		private MenuItem contextMenuItemUpdate;
		private MenuItem contextMenuItemCommit;
		private MenuItem menuItem7;
		private MenuItem contextMenuItemOpen;
		private MenuItem menuItem9;
		private MenuItem contextMenuItemChangeLog;
		private MenuItem contextMenuItemFullLog;
		private StatusBar statusBar;
		private Button btnAddFolder;
		private MenuItem menuItem4;
		private MenuItem menuItem5;
		private MenuItem contextMenuItemProperties;
		private MenuItem menuItem6;
		private MenuItem contextMenuItemForce;
		private MenuItem menuItemCheckNewVersion;
		private MenuItem menuItem8;
		private MenuItem menuItem11;
		private DragAndDropListView listViewFolders;
		private Panel panel1;
		private StatusBarPanel statusBarPanel1;
		private StatusBarPanel statusBarPanel2;
		private StatusBarPanel statusBarPanel3;
		private Button btnAddFile;
		private OpenFileDialog openFileDialog;
		private MenuItem menuItemAddFile;
		private MenuItem menuItemEdit;
		private MenuItem menuItemImportConfig;
		private MenuItem menuItemExportConfig;
		private Button btnDelete;
		
		#endregion

		#region Windows Form Designer generated code

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose (bool disposing)
		{
			if (disposing)
			{
				if (components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose (disposing);
		}


		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent( )
		{
			this.components = new System.ComponentModel.Container();
			System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(MainForm));
			this.trayContextMenu = new ContextMenu();
			this.menuItem_ShowList = new MenuItem();
			this.menuItem3 = new MenuItem();
			this.menuItem_UpdateAll = new MenuItem();
			this.menuItem2 = new MenuItem();
			this.menuItem_Exit = new MenuItem();
			this.folderBrowserDialog = new FolderBrowserDialog();
			this.statusUpdateTimer = new System.Timers.Timer();
			this.btnUpdate = new Button();
			this.btnChangeLog = new Button();
			this.contextMenu = new ContextMenu();
			this.contextMenuItemForce = new MenuItem();
			this.menuItem6 = new MenuItem();
			this.contextMenuItemChangeLog = new MenuItem();
			this.contextMenuItemUpdate = new MenuItem();
			this.menuItem9 = new MenuItem();
			this.contextMenuItemCommit = new MenuItem();
			this.menuItem7 = new MenuItem();
			this.contextMenuItemOpen = new MenuItem();
			this.contextMenuItemFullLog = new MenuItem();
			this.menuItem5 = new MenuItem();
			this.contextMenuItemProperties = new MenuItem();
			this.imageListFolderStatus = new ImageList(this.components);
			this.mainMenu = new MainMenu();
			this.menuItemFile = new MenuItem();
			this.menuItemImportConfig = new MenuItem();
			this.menuItemExportConfig = new MenuItem();
			this.menuItem11 = new MenuItem();
			this.menuItemExit = new MenuItem();
			this.menuItemEdit = new MenuItem();
			this.menuItemAddFolder = new MenuItem();
			this.menuItemAddFile = new MenuItem();
			this.menuItemDelete = new MenuItem();
			this.menuItem4 = new MenuItem();
			this.menuItemUpdateAll = new MenuItem();
			this.menuItem1 = new MenuItem();
			this.menuItemSettings = new MenuItem();
			this.menuItemHelp = new MenuItem();
			this.menuItemCheckNewVersion = new MenuItem();
			this.menuItem8 = new MenuItem();
			this.menuItemAbout = new MenuItem();
			this.btnOpenFolder = new Button();
			this.btnLog = new Button();
			this.statusBar = new StatusBar();
			this.statusBarPanel1 = new StatusBarPanel();
			this.statusBarPanel2 = new StatusBarPanel();
			this.statusBarPanel3 = new StatusBarPanel();
			this.btnCommit = new Button();
			this.btnAddFolder = new Button();
			this.btnDelete = new Button();
			this.listViewFolders = new DragNDrop.DragAndDropListView();
			this.panel1 = new Panel();
			this.btnAddFile = new Button();
			this.openFileDialog = new OpenFileDialog();
			((System.ComponentModel.ISupportInitialize)(this.statusUpdateTimer)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.statusBarPanel1)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.statusBarPanel2)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.statusBarPanel3)).BeginInit();
			this.panel1.SuspendLayout();
			this.SuspendLayout();
			// 
			// trayContextMenu
			// 
			this.trayContextMenu.MenuItems.AddRange(new MenuItem[] {
																							this.menuItem_ShowList,
																							this.menuItem3,
																							this.menuItem_UpdateAll,
																							this.menuItem2,
																							this.menuItem_Exit});
			// 
			// menuItem_ShowList
			// 
			this.menuItem_ShowList.Index = 0;
			this.menuItem_ShowList.Text = "Show Status Window";
			this.menuItem_ShowList.Click += new System.EventHandler(this.menuItem_ShowList_Click);
			// 
			// menuItem3
			// 
			this.menuItem3.Index = 1;
			this.menuItem3.Text = "-";
			// 
			// menuItem_UpdateAll
			// 
			this.menuItem_UpdateAll.Enabled = false;
			this.menuItem_UpdateAll.Index = 2;
			this.menuItem_UpdateAll.Text = "Update All";
			this.menuItem_UpdateAll.Click += new System.EventHandler(this.menuItem_UpdateAll_Click);
			// 
			// menuItem2
			// 
			this.menuItem2.Index = 3;
			this.menuItem2.Text = "-";
			// 
			// menuItem_Exit
			// 
			this.menuItem_Exit.Index = 4;
			this.menuItem_Exit.Text = "Exit";
			this.menuItem_Exit.Click += new System.EventHandler(this.menuItem_Exit_Click);
			// 
			// folderBrowserDialog
			// 
			this.folderBrowserDialog.Description = "Select folder controlled by Subversion";
			this.folderBrowserDialog.ShowNewFolderButton = false;
			// 
			// statusUpdateTimer
			// 
			this.statusUpdateTimer.AutoReset = false;
			this.statusUpdateTimer.SynchronizingObject = this;
			this.statusUpdateTimer.Elapsed += new System.Timers.ElapsedEventHandler(this.statusUpdateTimer_Elapsed);
			// 
			// btnUpdate
			// 
			this.btnUpdate.Enabled = false;
			this.btnUpdate.FlatStyle = FlatStyle.Popup;
			this.btnUpdate.Image = ((System.Drawing.Image)(resources.GetObject("btnUpdate.Image")));
			this.btnUpdate.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
			this.btnUpdate.Location = new System.Drawing.Point(101, 2);
			this.btnUpdate.Name = "btnUpdate";
			this.btnUpdate.Size = new System.Drawing.Size(67, 30);
			this.btnUpdate.TabIndex = 2;
			this.btnUpdate.Text = "Update";
			this.btnUpdate.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
			this.btnUpdate.Click += new System.EventHandler(this.btnUpdate_Click);
			// 
			// btnChangeLog
			// 
			this.btnChangeLog.Enabled = false;
			this.btnChangeLog.FlatStyle = FlatStyle.Popup;
			this.btnChangeLog.Image = ((System.Drawing.Image)(resources.GetObject("btnChangeLog.Image")));
			this.btnChangeLog.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
			this.btnChangeLog.Location = new System.Drawing.Point(4, 2);
			this.btnChangeLog.Name = "btnChangeLog";
			this.btnChangeLog.Size = new System.Drawing.Size(92, 30);
			this.btnChangeLog.TabIndex = 1;
			this.btnChangeLog.Text = "Change Log";
			this.btnChangeLog.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
			this.btnChangeLog.Click += new System.EventHandler(this.btnChangeLog_Click);
			// 
			// contextMenu
			// 
			this.contextMenu.MenuItems.AddRange(new MenuItem[] {
																						this.contextMenuItemForce,
																						this.menuItem6,
																						this.contextMenuItemChangeLog,
																						this.contextMenuItemUpdate,
																						this.menuItem9,
																						this.contextMenuItemCommit,
																						this.menuItem7,
																						this.contextMenuItemOpen,
																						this.contextMenuItemFullLog,
																						this.menuItem5,
																						this.contextMenuItemProperties});
			this.contextMenu.Popup += new System.EventHandler(this.contextMenu_Popup);
			// 
			// contextMenuItemForce
			// 
			this.contextMenuItemForce.Index = 0;
			this.contextMenuItemForce.Text = "Check Now...";
			this.contextMenuItemForce.Click += new System.EventHandler(this.contextMenuItemForce_Click);
			// 
			// menuItem6
			// 
			this.menuItem6.Index = 1;
			this.menuItem6.Text = "-";
			// 
			// contextMenuItemChangeLog
			// 
			this.contextMenuItemChangeLog.Index = 2;
			this.contextMenuItemChangeLog.Text = "Change Log...";
			this.contextMenuItemChangeLog.Click += new System.EventHandler(this.contextMenuItemChangeLog_Click);
			// 
			// contextMenuItemUpdate
			// 
			this.contextMenuItemUpdate.Index = 3;
			this.contextMenuItemUpdate.Text = "Update";
			this.contextMenuItemUpdate.Click += new System.EventHandler(this.contextMenuItemUpdate_Click);
			// 
			// menuItem9
			// 
			this.menuItem9.Index = 4;
			this.menuItem9.Text = "-";
			// 
			// contextMenuItemCommit
			// 
			this.contextMenuItemCommit.Index = 5;
			this.contextMenuItemCommit.Text = "Commit...";
			this.contextMenuItemCommit.Click += new System.EventHandler(this.contextMenuItemCommit_Click);
			// 
			// menuItem7
			// 
			this.menuItem7.Index = 6;
			this.menuItem7.Text = "-";
			// 
			// contextMenuItemOpen
			// 
			this.contextMenuItemOpen.Index = 7;
			this.contextMenuItemOpen.Text = "Open...";
			this.contextMenuItemOpen.Click += new System.EventHandler(this.contextMenuItemOpen_Click);
			// 
			// contextMenuItemFullLog
			// 
			this.contextMenuItemFullLog.Index = 8;
			this.contextMenuItemFullLog.Text = "Log...";
			this.contextMenuItemFullLog.Click += new System.EventHandler(this.contextMenuItemLog_Click);
			// 
			// menuItem5
			// 
			this.menuItem5.Index = 9;
			this.menuItem5.Text = "-";
			// 
			// contextMenuItemProperties
			// 
			this.contextMenuItemProperties.Index = 10;
			this.contextMenuItemProperties.Text = "Properties";
			this.contextMenuItemProperties.Click += new System.EventHandler(this.contextMenuItemProperties_Click);
			// 
			// imageListFolderStatus
			// 
			this.imageListFolderStatus.ColorDepth = ColorDepth.Depth32Bit;
			this.imageListFolderStatus.ImageSize = new System.Drawing.Size(16, 16);
			this.imageListFolderStatus.ImageStream = ((ImageListStreamer)(resources.GetObject("imageListFolderStatus.ImageStream")));
			this.imageListFolderStatus.TransparentColor = System.Drawing.Color.Transparent;
			// 
			// mainMenu
			// 
			this.mainMenu.MenuItems.AddRange(new MenuItem[] {
																					 this.menuItemFile,
																					 this.menuItemEdit,
																					 this.menuItem4,
																					 this.menuItemHelp});
			// 
			// menuItemFile
			// 
			this.menuItemFile.Index = 0;
			this.menuItemFile.MenuItems.AddRange(new MenuItem[] {
																						 this.menuItemImportConfig,
																						 this.menuItemExportConfig,
																						 this.menuItem11,
																						 this.menuItemExit});
			this.menuItemFile.Text = "&File";
			// 
			// menuItemImportConfig
			// 
			this.menuItemImportConfig.Index = 0;
			this.menuItemImportConfig.Text = "Import config...";
			this.menuItemImportConfig.Click += new System.EventHandler(this.menuItemImportConfig_Click);
			// 
			// menuItemExportConfig
			// 
			this.menuItemExportConfig.Index = 1;
			this.menuItemExportConfig.Text = "Export config...";
			this.menuItemExportConfig.Click += new System.EventHandler(this.menuItemExportConfig_Click);
			// 
			// menuItem11
			// 
			this.menuItem11.Index = 2;
			this.menuItem11.Text = "-";
			// 
			// menuItemExit
			// 
			this.menuItemExit.Index = 3;
			this.menuItemExit.Text = "&Exit";
			this.menuItemExit.Click += new System.EventHandler(this.menuItemExit_Click);
			// 
			// menuItemEdit
			// 
			this.menuItemEdit.Index = 1;
			this.menuItemEdit.MenuItems.AddRange(new MenuItem[] {
																						 this.menuItemAddFolder,
																						 this.menuItemAddFile,
																						 this.menuItemDelete});
			this.menuItemEdit.Text = "&Edit";
			// 
			// menuItemAddFolder
			// 
			this.menuItemAddFolder.Index = 0;
			this.menuItemAddFolder.Text = "Add folder...";
			this.menuItemAddFolder.Click += new System.EventHandler(this.menuItemAddFolder_Click);
			// 
			// menuItemAddFile
			// 
			this.menuItemAddFile.Index = 1;
			this.menuItemAddFile.Text = "Add file...";
			this.menuItemAddFile.Click += new System.EventHandler(this.menuItemAddFile_Click);
			// 
			// menuItemDelete
			// 
			this.menuItemDelete.Enabled = false;
			this.menuItemDelete.Index = 2;
			this.menuItemDelete.Text = "Delete...";
			this.menuItemDelete.Click += new System.EventHandler(this.menuItemDelete_Click);
			// 
			// menuItem4
			// 
			this.menuItem4.Index = 2;
			this.menuItem4.MenuItems.AddRange(new MenuItem[] {
																					  this.menuItemUpdateAll,
																					  this.menuItem1,
																					  this.menuItemSettings});
			this.menuItem4.Text = "&Tools";
			// 
			// menuItemUpdateAll
			// 
			this.menuItemUpdateAll.Enabled = false;
			this.menuItemUpdateAll.Index = 0;
			this.menuItemUpdateAll.Text = "Update All";
			this.menuItemUpdateAll.Click += new System.EventHandler(this.menuItemUpdateAll_Click);
			// 
			// menuItem1
			// 
			this.menuItem1.Index = 1;
			this.menuItem1.Text = "-";
			// 
			// menuItemSettings
			// 
			this.menuItemSettings.Index = 2;
			this.menuItemSettings.Text = "&Settings...";
			this.menuItemSettings.Click += new System.EventHandler(this.menuItemSettings_Click);
			// 
			// menuItemHelp
			// 
			this.menuItemHelp.Index = 3;
			this.menuItemHelp.MenuItems.AddRange(new MenuItem[] {
																						 this.menuItemCheckNewVersion,
																						 this.menuItem8,
																						 this.menuItemAbout});
			this.menuItemHelp.Text = "&Help";
			// 
			// menuItemCheckNewVersion
			// 
			this.menuItemCheckNewVersion.Index = 0;
			this.menuItemCheckNewVersion.Text = "Check for new version";
			this.menuItemCheckNewVersion.Click += new System.EventHandler(this.menuItemCheckNewVersion_Click);
			// 
			// menuItem8
			// 
			this.menuItem8.Index = 1;
			this.menuItem8.Text = "-";
			// 
			// menuItemAbout
			// 
			this.menuItemAbout.Index = 2;
			this.menuItemAbout.Text = "&About...";
			this.menuItemAbout.Click += new System.EventHandler(this.menuItemAbout_Click);
			// 
			// btnOpenFolder
			// 
			this.btnOpenFolder.Enabled = false;
			this.btnOpenFolder.FlatStyle = FlatStyle.Popup;
			this.btnOpenFolder.Image = ((System.Drawing.Image)(resources.GetObject("btnOpenFolder.Image")));
			this.btnOpenFolder.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
			this.btnOpenFolder.Location = new System.Drawing.Point(245, 2);
			this.btnOpenFolder.Name = "btnOpenFolder";
			this.btnOpenFolder.Size = new System.Drawing.Size(67, 30);
			this.btnOpenFolder.TabIndex = 4;
			this.btnOpenFolder.Text = "Open";
			this.btnOpenFolder.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
			this.btnOpenFolder.Click += new System.EventHandler(this.btnOpenFolder_Click);
			// 
			// btnLog
			// 
			this.btnLog.Enabled = false;
			this.btnLog.FlatStyle = FlatStyle.Popup;
			this.btnLog.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
			this.btnLog.Location = new System.Drawing.Point(317, 2);
			this.btnLog.Name = "btnLog";
			this.btnLog.Size = new System.Drawing.Size(35, 30);
			this.btnLog.TabIndex = 5;
			this.btnLog.Text = "Log";
			this.btnLog.Click += new System.EventHandler(this.btnLog_Click);
			// 
			// statusBar
			// 
			this.statusBar.Location = new System.Drawing.Point(0, 349);
			this.statusBar.Name = "statusBar";
			this.statusBar.Panels.AddRange(new StatusBarPanel[] {
																						 this.statusBarPanel1,
																						 this.statusBarPanel2,
																						 this.statusBarPanel3});
			this.statusBar.ShowPanels = true;
			this.statusBar.Size = new System.Drawing.Size(600, 20);
			this.statusBar.TabIndex = 7;
			this.statusBar.PanelClick += new StatusBarPanelClickEventHandler(this.statusBar_PanelClick);
			// 
			// statusBarPanel1
			// 
			this.statusBarPanel1.AutoSize = StatusBarPanelAutoSize.Spring;
			this.statusBarPanel1.Width = 464;
			// 
			// statusBarPanel2
			// 
			this.statusBarPanel2.MinWidth = 20;
			this.statusBarPanel2.Width = 20;
			// 
			// statusBarPanel3
			// 
			this.statusBarPanel3.MinWidth = 100;
			// 
			// btnCommit
			// 
			this.btnCommit.Enabled = false;
			this.btnCommit.FlatStyle = FlatStyle.Popup;
			this.btnCommit.Image = ((System.Drawing.Image)(resources.GetObject("btnCommit.Image")));
			this.btnCommit.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
			this.btnCommit.Location = new System.Drawing.Point(173, 2);
			this.btnCommit.Name = "btnCommit";
			this.btnCommit.Size = new System.Drawing.Size(67, 30);
			this.btnCommit.TabIndex = 3;
			this.btnCommit.Text = "Commit";
			this.btnCommit.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
			this.btnCommit.Click += new System.EventHandler(this.btnCommit_Click);
			// 
			// btnAddFolder
			// 
			this.btnAddFolder.Anchor = ((AnchorStyles)((AnchorStyles.Top | AnchorStyles.Right)));
			this.btnAddFolder.FlatStyle = FlatStyle.Popup;
			this.btnAddFolder.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(204)));
			this.btnAddFolder.Image = ((System.Drawing.Image)(resources.GetObject("btnAddFolder.Image")));
			this.btnAddFolder.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
			this.btnAddFolder.Location = new System.Drawing.Point(496, 2);
			this.btnAddFolder.Name = "btnAddFolder";
			this.btnAddFolder.Size = new System.Drawing.Size(30, 30);
			this.btnAddFolder.TabIndex = 6;
			this.btnAddFolder.Click += new System.EventHandler(this.menuItemAddFolder_Click);
			// 
			// btnDelete
			// 
			this.btnDelete.Anchor = ((AnchorStyles)((AnchorStyles.Top | AnchorStyles.Right)));
			this.btnDelete.Enabled = false;
			this.btnDelete.FlatStyle = FlatStyle.Popup;
			this.btnDelete.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(204)));
			this.btnDelete.Image = ((System.Drawing.Image)(resources.GetObject("btnDelete.Image")));
			this.btnDelete.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
			this.btnDelete.Location = new System.Drawing.Point(566, 2);
			this.btnDelete.Name = "btnDelete";
			this.btnDelete.Size = new System.Drawing.Size(30, 30);
			this.btnDelete.TabIndex = 7;
			this.btnDelete.Click += new System.EventHandler(this.menuItemDelete_Click);
			// 
			// listViewFolders
			// 
			this.listViewFolders.AllowDrop = true;
			this.listViewFolders.AllowReorder = true;
			this.listViewFolders.ContextMenu = this.contextMenu;
			this.listViewFolders.Dock = DockStyle.Fill;
			this.listViewFolders.HideSelection = false;
			this.listViewFolders.LineColor = System.Drawing.Color.LightGray;
			this.listViewFolders.Location = new System.Drawing.Point(0, 37);
			this.listViewFolders.MultiSelect = false;
			this.listViewFolders.Name = "listViewFolders";
			this.listViewFolders.Size = new System.Drawing.Size(600, 312);
			this.listViewFolders.SmallImageList = this.imageListFolderStatus;
			this.listViewFolders.TabIndex = 0;
			this.listViewFolders.View = View.List;
			this.listViewFolders.KeyDown += new KeyEventHandler(this.listViewFolders_KeyDown);
			this.listViewFolders.DoubleClick += new System.EventHandler(this.listViewFolders_DoubleClick);
			this.listViewFolders.DragDrop += new DragEventHandler(this.listViewFolders_DragDrop);
			this.listViewFolders.SelectedIndexChanged += new System.EventHandler(this.listViewFolders_SelectedIndexChanged);
			// 
			// panel1
			// 
			this.panel1.Controls.Add(this.btnAddFile);
			this.panel1.Dock = DockStyle.Top;
			this.panel1.Location = new System.Drawing.Point(0, 0);
			this.panel1.Name = "panel1";
			this.panel1.Size = new System.Drawing.Size(600, 37);
			this.panel1.TabIndex = 8;
			// 
			// btnAddFile
			// 
			this.btnAddFile.Anchor = ((AnchorStyles)((AnchorStyles.Top | AnchorStyles.Right)));
			this.btnAddFile.FlatStyle = FlatStyle.Popup;
			this.btnAddFile.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(204)));
			this.btnAddFile.Image = ((System.Drawing.Image)(resources.GetObject("btnAddFile.Image")));
			this.btnAddFile.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
			this.btnAddFile.Location = new System.Drawing.Point(531, 2);
			this.btnAddFile.Name = "btnAddFile";
			this.btnAddFile.Size = new System.Drawing.Size(30, 30);
			this.btnAddFile.TabIndex = 7;
			this.btnAddFile.Click += new System.EventHandler(this.menuItemAddFile_Click);
			// 
			// openFileDialog
			// 
			this.openFileDialog.Title = "Select file controlled by Subversion";
			// 
			// MainForm
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(600, 369);
			this.ContextMenu = this.contextMenu;
			this.Controls.Add(this.listViewFolders);
			this.Controls.Add(this.btnCommit);
			this.Controls.Add(this.btnAddFolder);
			this.Controls.Add(this.btnDelete);
			this.Controls.Add(this.btnLog);
			this.Controls.Add(this.btnOpenFolder);
			this.Controls.Add(this.statusBar);
			this.Controls.Add(this.btnUpdate);
			this.Controls.Add(this.btnChangeLog);
			this.Controls.Add(this.panel1);
			this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
			this.KeyPreview = true;
			this.MaximizeBox = false;
			this.Menu = this.mainMenu;
			this.MinimumSize = new System.Drawing.Size(512, 160);
			this.Name = "MainForm";
			this.Text = "SVN Notifier";
			this.KeyDown += new KeyEventHandler(this.MainForm_KeyDown);
			this.Closing += new System.ComponentModel.CancelEventHandler(this.MainForm_Closing);
			this.Activated += new System.EventHandler(this.MainForm_Activated);
			this.Deactivate += new System.EventHandler(this.MainForm_Deactivate);
			((System.ComponentModel.ISupportInitialize)(this.statusUpdateTimer)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.statusBarPanel1)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.statusBarPanel2)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.statusBarPanel3)).EndInit();
			this.panel1.ResumeLayout(false);
			this.ResumeLayout(false);

		}

		#endregion

		//////////////////////////////////////////////////////////////////////// 

		[DllImport("psapi")]
		private static extern int EmptyWorkingSet(IntPtr handle);
		
		////////////////////////////////////////////////////////////////////////
		
		private NotifyIconEx notifyIcon;
		private Icon trayIcon_NeedUpdate	= null;
		private Icon trayIcon_UpToDate		= null;
		private Icon trayIcon_Unknown		= null;
		private Icon trayIcon_Error	= null;
		private Icon errorLogIcon = null;
		
		private SvnFolderCollection folders = new SvnFolderCollection();
		private Hashtable errorLog = new Hashtable ();
		private bool reupdateStatus;
		private ManualResetEvent updateNotInProgress = new ManualResetEvent (true);
		private Queue forcedFolders = Queue.Synchronized (new Queue());


		public MainForm( )
		{
			InitializeComponent();

			if (Config.HideOnStartup)
			{
				WindowState = FormWindowState.Minimized;
				ShowInTaskbar = false;
			}

			// Load icons from resources
			trayIcon_NeedUpdate  = new Icon (GetType(), "Icons.TrayIcon_NeedUpdate.ico");
			trayIcon_UpToDate    = new Icon (GetType(), "Icons.TrayIcon_UpToDate.ico"); 
			trayIcon_Unknown     = new Icon (GetType(), "Icons.TrayIcon_Unknown.ico");
			trayIcon_Error       = new Icon (GetType(), "Icons.TrayIcon_Error.ico");
			errorLogIcon         = new Icon (GetType(), "Icons.Errors.ico");
			
			// Initialize tray notify icon
			notifyIcon = new NotifyIconEx();
			notifyIcon.Text = Application.ProductName;
			Icon = notifyIcon.Icon = trayIcon_Unknown;
			notifyIcon.Visible = true;
			notifyIcon.ContextMenu = trayContextMenu;
			notifyIcon.Click += new EventHandler (NotifyIcon_Click);
			notifyIcon.DoubleClick += new EventHandler (NotifyIcon_Click);
			notifyIcon.BalloonClick += new EventHandler (NotifyIcon_BalloonClick);

			SvnTools.ErrorAdded += new SvnErrorAddedHandler (OnErrorAdded);

			FormInit ();
		}


		private void FormInit()
		{
			listViewFolders.Clear();

			folders = Config.ReadSvnFolders();

			foreach (SvnFolder folder in folders)
			{
				ListViewItem item = new ListViewItem (folder.Path, imageIndex_Unknown);

				if (folder.Disable)
				{
					item.Font = new Font (listViewFolders.Font, FontStyle.Strikeout);
					item.ForeColor = Color.LightGray;
				}

				listViewFolders.Items.Add (item);
			}

			UpdateFormSize();

			UpdateListViewFolderNames();

			BeginUpdateFolderStatuses();
		}


		private void UpdateFormSize()
		{
			int[] size = Config.ReadMainFormSize ();

			if ((size[0] == 0) || (size[1] == 0))
			{
				Config.SaveMainFormSize (Width, Height);
			}
			else
			{
				Width = size[0];
				Height = size[1];
			}
		}


		//////////////////////////////////////////////////////////////////////////////

		private int GetFoldersCommonPartLength ()
		{
			if (folders.Count < 2) return 0;
			
			string path0 = folders[0].Path;
			
			int len = 0;
			for (int i = 0; i < path0.Length; i++)
				for (int f = 1; f < folders.Count; f++)
				{
					string path = folders[f].Path;
					if (i == path.Length-1) return len;
					if (path0[i] != path[i]) return len;
					if (path0[i] == '\\') len = i+1;
				}
			return len;
		}


		private void UpdateListViewFolderNames ()
		{
			int i = GetFoldersCommonPartLength();

			for (int f = 0; f < folders.Count; f++)
			{
				folders[f].VisiblePath = (i > 0 ? "\u2026" : "") + folders[f].Path.Substring (i);
				listViewFolders.Items[f].Tag = folders[f];
				listViewFolders.Items[f].Text = folders[f].VisiblePath;
			}
		}

		//////////////////////////////////////////////////////////////////////////////
		
		private const int imageIndex_UpToDate				= 0;
		private const int imageIndex_NeedUpdate				= 1;
		private const int imageIndex_Bad					= 2;
		private const int imageIndex_Unknown				= 3;
		private const int imageIndex_UpToDate_Modified		= 4;
		private const int imageIndex_NeedUpdate_Modified	= 5;
		
		private int GetFolderStatusImageIndex (SvnFolderStatus folderStatus)
		{
			switch (folderStatus)
			{
				case SvnFolderStatus.NeedUpdate_Modified:	
					return imageIndex_NeedUpdate_Modified;
					
				case SvnFolderStatus.UpToDate_Modified:	
					return imageIndex_UpToDate_Modified;
					
				case SvnFolderStatus.UpToDate:	
					return imageIndex_UpToDate;	
								
				case SvnFolderStatus.NeedUpdate:
					return imageIndex_NeedUpdate;
								
				case SvnFolderStatus.Error:
					return imageIndex_Bad;
				
				default:
					return imageIndex_Unknown;
			}		
		}
		

		//////////////////////////////////////////////////////////////////////////////

		#region Main menu handlers


		private void menuItemExportConfig_Click (object sender, EventArgs e)
		{
			SaveFileDialog sfd = new SaveFileDialog();
			sfd.FileName = "SVN_Notifier.ini";
			sfd.Filter = "Ini files (*.ini)|*.ini|All files (*.*)|*.*";
			sfd.RestoreDirectory = true;
 
			if (sfd.ShowDialog() == DialogResult.OK)
			{
				try
				{
					File.Copy (Config.FileName, sfd.FileName, true);
				}
				catch (Exception ex)
				{
					ShowError (ex.Message.ToString());
				}
			}
		}


		private void menuItemImportConfig_Click (object sender, EventArgs e)
		{
			OpenFileDialog ofd = new OpenFileDialog();
			ofd.Filter = "Ini files (*.ini)|*.ini|All files (*.*)|*.*";
			ofd.RestoreDirectory = true;

			if (ofd.ShowDialog() == DialogResult.OK)
			{
				if (MessageBox.Show ("All current settings will be lost.\n\nDo you really want to change the settings?", "Attention", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
				{
					try
					{
						File.Copy (ofd.FileName, Config.FileName, true);
						Config.Init();
						FormInit();
					}
					catch (Exception ex)
					{
						ShowError (ex.Message.ToString());
					}
				}
			}
		}


		private void menuItemSettings_Click(object sender, EventArgs e)
		{
			new SettingsForm().ShowDialog (this);
		}


		private void menuItemExit_Click (object sender, EventArgs e)
		{
			Application.Exit();
		}

		
		private void menuItemAbout_Click(object sender, EventArgs e)
		{
			new AboutForm().ShowDialog (this);
		}

		
		private void menuItemUpdateAll_Click(object sender, EventArgs e)
		{
			WindowState = FormWindowState.Minimized;
			UpdateAll();
		}


		private void menuItemAddFolder_Click (object sender, EventArgs e)
		{
			if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
			{
				string path = folderBrowserDialog.SelectedPath;

				if (! folders.ContainsPath (path))
				{
					if (Directory.Exists (path + @"\.svn") || Directory.Exists (path + @"\_svn"))
					{
						folders.Add (new SvnFolder (path, SvnFolder.PathType.Directory));

						listViewFolders.Items.Add (new ListViewItem (path, imageIndex_Unknown));
						UpdateListViewFolderNames();

						Config.SaveSvnFolders (folders);
					
						UpdateTray (false);
						BeginUpdateFolderStatuses ();
					}
					else
					{
						MessageBox.Show ("This folder is not under SVN", "SVN Notifier", MessageBoxButtons.OK, MessageBoxIcon.Error);
					}
				}
				else
					SelectFolder (path);
			}
		}


		private void menuItemAddFile_Click(object sender, EventArgs e)
		{
			if (openFileDialog.ShowDialog() == DialogResult.OK)
			{
				string fileName = openFileDialog.FileName;
				string path = Path.GetDirectoryName (fileName);

				if (! folders.ContainsPath (fileName))
				{
					if (Directory.Exists (path + @"\.svn") || Directory.Exists (path + @"\_svn"))
					{
						folders.Add (new SvnFolder (fileName, SvnFolder.PathType.File));

						listViewFolders.Items.Add (new ListViewItem (fileName, imageIndex_Unknown));
						UpdateListViewFolderNames();

						Config.SaveSvnFolders (folders);
					
						UpdateTray (false);
						BeginUpdateFolderStatuses ();
					}
					else
					{
						MessageBox.Show ("This file is not under SVN", "SVN Notifier", MessageBoxButtons.OK, MessageBoxIcon.Error);
					}
				}
				else
					SelectFolder (fileName);
			}
		}

		
		private void menuItemDelete_Click(object sender, EventArgs e)
		{
			if (listViewFolders.SelectedIndices.Count > 0)
			{
				int selectedIndex = listViewFolders.SelectedIndices [0];
				string path = folders [listViewFolders.SelectedIndices [0]].Path;

				if (MessageBox.Show ("Are you sure to remove " + path + " from list?", "SVN Notifier", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK)
					return;

				folders.RemoveAt (selectedIndex);

				listViewFolders.Items.RemoveAt (selectedIndex);
				UpdateListViewFolderNames();
				newNonUpdatedFolders.Clear();

				Config.SaveSvnFolders (folders);
				
				UpdateTray (true);
				BeginUpdateFolderStatuses ();
			}
		}


		private void menuItemCheckNewVersion_Click(object sender, EventArgs e)
		{
			forcedCheckForNewVersion = true;
			BeginUpdateFolderStatuses();
		}
		
		#endregion

		//////////////////////////////////////////////////////////////////////////////

		#region Toolbar button handlers

		private void btnUpdate_Click (object sender, EventArgs e)
		{
			UpdateFolder();
		}


		private void btnCommit_Click(object sender, EventArgs e)
		{
			CommitFolder();
		}

		
		private void btnOpenFolder_Click (object sender, EventArgs e)
		{
			OpenFolder();
		}
		

		private void btnChangeLog_Click (object sender, EventArgs e)
		{
			ShowChangeLog();
		}
		
		
		private void btnLog_Click(object sender, EventArgs e)
		{
			ShowFullLog();
		}


		#endregion 

		//////////////////////////////////////////////////////////////////////////////

		#region Context menu handlers

		private void contextMenuItemForce_Click(object sender, EventArgs e)
		{
			if (listViewFolders.SelectedIndices.Count == 0)
				return;

			int selectedIndex = listViewFolders.SelectedIndices[0];
			forcedFolders.Enqueue (folders[selectedIndex]);
			BeginUpdateFolderStatuses();
		}


		private void contextMenuItemUpdate_Click(object sender, EventArgs e)
		{
			UpdateFolder();
		}


		private void contextMenuItemCommit_Click(object sender, EventArgs e)
		{
			CommitFolder();
		}


		private void contextMenuItemOpen_Click(object sender, EventArgs e)
		{
			OpenFolder();
		}


		private void contextMenuItemChangeLog_Click(object sender, EventArgs e)
		{
			ShowChangeLog();
		}


		private void contextMenuItemLog_Click(object sender, EventArgs e)
		{
			ShowFullLog();
		}


		private void contextMenuItemProperties_Click (object sender, EventArgs e)
		{
			int selectedIndex = listViewFolders.SelectedIndices[0];

			if (new SettingsProjectForm (folders[selectedIndex]).ShowDialog (this) == DialogResult.OK)
			{
				if (folders[selectedIndex].Disable)
				{
					listViewFolders.Items[selectedIndex].Font = new Font (listViewFolders.Font, FontStyle.Strikeout);
					listViewFolders.Items[selectedIndex].ForeColor = Color.LightGray;
				}
				else
				{
					listViewFolders.Items[selectedIndex].Font = listViewFolders.Font;
					listViewFolders.Items[selectedIndex].ForeColor = SystemColors.WindowText;
				}

				newNonUpdatedFolders.Clear();

				Config.SaveSvnFolders (folders);
				
				UpdateTray (true);
				BeginUpdateFolderStatuses ();
			}
		}


		private void contextMenu_Popup(object sender, EventArgs e)
		{
			UpdateContextMenuItem ();
			UpdateContextMenuDefaultItem ();
		}


		private void UpdateContextMenuItem ()
		{
			contextMenuItemForce.Enabled =
				contextMenuItemCommit.Enabled =
				contextMenuItemUpdate.Enabled =
				contextMenuItemOpen.Enabled =
				contextMenuItemChangeLog.Enabled =
				contextMenuItemFullLog.Enabled =
				contextMenuItemProperties.Enabled = false;
			
			if (listViewFolders.SelectedIndices.Count == 0) return;

			int selectedIndex = listViewFolders.SelectedIndices[0];
			
			switch (folders[selectedIndex].Status)
			{
				case SvnFolderStatus.NeedUpdate:
					contextMenuItemForce.Enabled =
						contextMenuItemUpdate.Enabled =
						contextMenuItemOpen.Enabled =
						contextMenuItemChangeLog.Enabled =
						contextMenuItemFullLog.Enabled =
						contextMenuItemProperties.Enabled = true;
					break;
			
				case SvnFolderStatus.NeedUpdate_Modified:
					contextMenuItemForce.Enabled =
						contextMenuItemCommit.Enabled =
						contextMenuItemUpdate.Enabled =
						contextMenuItemOpen.Enabled =
						contextMenuItemChangeLog.Enabled =
						contextMenuItemFullLog.Enabled =
						contextMenuItemProperties.Enabled = true;
					break;
			
				case SvnFolderStatus.UpToDate_Modified:
					contextMenuItemForce.Enabled =
						contextMenuItemCommit.Enabled =
						contextMenuItemOpen.Enabled =
						contextMenuItemFullLog.Enabled =
						contextMenuItemProperties.Enabled = true;
					break;

				case SvnFolderStatus.UpToDate:
					contextMenuItemForce.Enabled =
						contextMenuItemOpen.Enabled =
						contextMenuItemFullLog.Enabled =
						contextMenuItemProperties.Enabled = true;
					break;

				case SvnFolderStatus.Unknown:
					contextMenuItemForce.Enabled =
						contextMenuItemOpen.Enabled =
						contextMenuItemProperties.Enabled = true;
					break;

				case SvnFolderStatus.Error:
					contextMenuItemForce.Enabled =
						contextMenuItemProperties.Enabled = true;
					break;
			}
		}


		private void UpdateContextMenuDefaultItem ()
		{
			contextMenuItemChangeLog.DefaultItem =
				contextMenuItemFullLog.DefaultItem =
				contextMenuItemCommit.DefaultItem =
				contextMenuItemUpdate.DefaultItem =
				contextMenuItemOpen.DefaultItem = false;
			
			switch(Config.ItemDoubleClickAction)
			{
				case Config.Action.openAction:
					contextMenuItemOpen.DefaultItem = true;
					break;

				case Config.Action.logAction:
					if (contextMenuItemChangeLog.Enabled)
						contextMenuItemChangeLog.DefaultItem = true;
					else if (contextMenuItemFullLog.Enabled)
						contextMenuItemFullLog.DefaultItem = true;

					break;

				case Config.Action.updateAction:
					contextMenuItemUpdate.DefaultItem = true;
					break;

				case Config.Action.commitAction:
					contextMenuItemCommit.DefaultItem = true;
					break;
			}
		}


		#endregion 

		//////////////////////////////////////////////////////////////////////////////
		
		#region Tray menu handlers

		private void menuItem_ShowList_Click (object sender, EventArgs e)
		{
			ShowFolderList ();
		}

		
		private void menuItem_Exit_Click (object sender, EventArgs e)
		{
			Application.Exit();
		}

		private void menuItem_UpdateAll_Click (object sender, EventArgs e)
		{
			UpdateAll();
		}

		#endregion
		
		////////////////////////////////////////////////////////////////////////////////////

		#region listViewFolders handlers

		private void listViewFolders_SelectedIndexChanged (object sender, EventArgs e)
		{
			if (listViewFolders.SelectedIndices.Count > 0)
			{
				SvnFolder folder = folders [listViewFolders.SelectedIndices[0]];

				btnChangeLog.Enabled = btnUpdate.Enabled = btnLog.Enabled = false;
				
				if ((folder.Status == SvnFolderStatus.NeedUpdate) || (folder.Status == SvnFolderStatus.NeedUpdate_Modified))
					btnChangeLog.Enabled = btnUpdate.Enabled = btnLog.Enabled = true;
				else if ((folder.Status == SvnFolderStatus.UpToDate) || (folder.Status == SvnFolderStatus.UpToDate_Modified))
					btnLog.Enabled = true;
				
				if ((folder.Status == SvnFolderStatus.NeedUpdate_Modified) || (folder.Status == SvnFolderStatus.UpToDate_Modified))
					btnCommit.Enabled = true;

				menuItemDelete.Enabled = true;
				btnDelete.Enabled = true;
				btnOpenFolder.Enabled = Directory.Exists (folder.Path) || File.Exists (folder.Path);

				Text = Application.ProductName + " - " + folder.Path;
			}
			else
			{
				btnChangeLog.Enabled = false;
				btnUpdate.Enabled = false;
				btnCommit.Enabled = false;
				menuItemDelete.Enabled = false;
				btnDelete.Enabled = false;
				btnOpenFolder.Enabled = false;
				btnLog.Enabled = false;

				Text = Application.ProductName;
			}
		}


		private void listViewFolders_KeyDown(object sender, KeyEventArgs e)
		{
			switch (e.KeyCode)
			{
				case Keys.Delete:
					menuItemDelete_Click (sender, null);
					break;

				case Keys.Insert:
					menuItemAddFolder_Click (sender, null);
					break;
					
				case Keys.Enter:
					listViewFolders_DoubleClick (sender, null);
					break;
			}
		}


		private void listViewFolders_DoubleClick(object sender, EventArgs e)
		{
			switch (Config.ItemDoubleClickAction)
			{
				case Config.Action.openAction:
					if (btnOpenFolder.Enabled)
						OpenFolder();
					break;

				case Config.Action.logAction:
					if (btnChangeLog.Enabled)
						ShowChangeLog();
					else if (btnLog.Enabled)
						ShowFullLog();
					break;

				case Config.Action.updateAction:
					if (btnUpdate.Enabled)
						UpdateFolder();
					break;

				case Config.Action.commitAction:
					if (btnCommit.Enabled)
						CommitFolder();
					break;

				case Config.Action.checkNow:
					int selectedIndex = listViewFolders.SelectedIndices[0];
					forcedFolders.Enqueue (folders[selectedIndex]);
					BeginUpdateFolderStatuses();
					break;
			}
		}


		private void listViewFolders_DragDrop (object sender, DragEventArgs e)
		{
			try
			{
				DragAndDropListView.DragItemData data = (DragAndDropListView.DragItemData) e.Data.GetData (typeof (DragAndDropListView.DragItemData));
				ListViewItem item = (ListViewItem) data.DragItems[0];

				folders.Remove ((SvnFolder) item.Tag);
				folders.Insert (item.Index, (SvnFolder)item.Tag);

				Config.SaveSvnFolders (folders);
			}
			catch (Exception ex)
			{
				OnThreadException (this, new ThreadExceptionEventArgs (ex));
			}
		}


		#endregion

		////////////////////////////////////////////////////////////////////////////////////

		#region NotifyIcon handlers

		private void NotifyIcon_Click (object sender, EventArgs e)
		{
			ShowFolderList ();
		}


		private void NotifyIcon_BalloonClick (object sender, EventArgs e)
		{
			ShowFolderList ();
			
			if (firstBalloonPath != null)
				SelectFolder (firstBalloonPath);
		}


		#endregion

		////////////////////////////////////////////////////////////////////////////////////
		
		#region MainForm handlers
		
		private void MainForm_KeyDown (object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Escape)
				Hide();

			e.Handled = false;
		}


		private void MainForm_Closing (object sender, CancelEventArgs e)
		{
			if (!sessionEndInProgress)
			{
				e.Cancel = true;
				Hide();
			}
		}


		private void MainForm_Activated (object sender, EventArgs e)
		{
			FormStateChanged (true);
			BeginUpdateFolderStatuses();
		}


		private void MainForm_Deactivate (object sender, EventArgs e)
		{
			FormStateChanged (false);
		}


		#endregion

		////////////////////////////////////////////////////////////////////////////////////

		private void UpdateFolder()
		{
			if (listViewFolders.SelectedIndices.Count == 0)
				return;

			int selectedIndex = listViewFolders.SelectedIndices[0];
			SvnFolder folder = folders[selectedIndex];

			if (Config.ChangeLogBeforeUpdate && (folder.headRevision == 0))
			{
				MessageBox.Show ("You need to check Change Log before use Update!", 
					"SVN Notifier", MessageBoxButtons.OK, MessageBoxIcon.Stop);
				return;
			}

			btnUpdate.Enabled = contextMenuItemUpdate.Enabled = contextMenuItemForce.Enabled = false;
			folder.Status = SvnFolderStatus.Unknown;
			listViewFolders.Items [selectedIndex].ImageIndex = imageIndex_Unknown;
			newNonUpdatedFolders.Clear();
			
			statusBar.Panels[0].Text = "Updating '" + folder.Path + "'...";
			UpdateTray (true);
			Refresh();				// Show "Unknown" folder status during updating

			updateNotInProgress.Reset();
			BeginUpdateFolderStatuses();

			SvnTools.Update (folder);

			forcedFolders.Enqueue (folder);

			updateNotInProgress.Set();
		}
		
		
		private void CommitFolder()
		{
			if (listViewFolders.SelectedIndices.Count == 0)
				return;

			int selectedIndex = listViewFolders.SelectedIndices[0];
			SvnTools.Commit (folders[selectedIndex]);
		}


		private void UpdateAll()
		{
			newNonUpdatedFolders.Clear();
			statusBar.Panels[0].Text = "Updating all...";
			UpdateTray (true);

			BeginUpdateFolderStatuses();

			btnUpdate.Enabled = contextMenuItemUpdate.Enabled = contextMenuItemForce.Enabled = menuItem_UpdateAll.Enabled = false;

			foreach (SvnFolder folder in folders)
				if ((folder.Status == SvnFolderStatus.NeedUpdate) || (folder.Status == SvnFolderStatus.NeedUpdate_Modified))
				{
					folder.Status = SvnFolderStatus.Unknown;
					listViewFolders.Items [folders.IndexOf (folder)].ImageIndex = imageIndex_Unknown;

					SvnTools.BeginUpdateSilently (folder);
				}
			UpdateTray (true);
		}
		
		
		private void OpenFolder()
		{
			int selectedIndex = listViewFolders.SelectedIndices[0];
			Process.Start (folders[selectedIndex].Path + @"\");
		}
		
		
		private void ShowChangeLog()
		{
			int selectedIndex = listViewFolders.SelectedIndices [0];
			SvnTools.OpenChangeLogWindow (folders [selectedIndex]);
		}
		

		private void ShowFullLog()
		{
			int selectedIndex = listViewFolders.SelectedIndices [0];
			SvnTools.OpenLogWindow (folders [selectedIndex].Path);
		}
		
		
		private void SelectFolder (string path)
		{
			foreach (ListViewItem item in listViewFolders.Items)
				if (item.Text == path)
				{
					item.Selected = true;
					break;
				}
		}

		
		private void ShowFolderList ()
		{
			Show();
			if(WindowState == FormWindowState.Minimized)
				WindowState = FormWindowState.Normal;
			Activate();
		}
		
		
		////////////////////////////////////////////////////////////////////////////////////
		
		private SvnFolderCollection newNonUpdatedFolders = new SvnFolderCollection();
		private delegate void UpdateListViewMethod (SvnFolder folder, SvnFolderStatus folderStatus, DateTime statusTime);
		private delegate void SetStatusBarTextMethod (string text);
		private delegate void UpdateErrorLogMethod (string path, string error);
		private delegate void CheckedInvokeMethod (Delegate method, object[] args);
		private delegate void ShowUpdateErrorsMethod (SvnFolderProcess sfp);

		internal static Thread statusThread;
		string firstBalloonPath;
		private bool formIsActive = false;
		private IntPtr currentProcessHandle = Process.GetCurrentProcess().Handle;
		private bool repeatInvoke;

		////////////////////////////////////////////////////////////////////////////////////

		#region Checking for new version

		private bool forcedCheckForNewVersion = false;							// Means manually called from main menu
		private DateTime lastTimeOfCheckForNewVersion = DateTime.MinValue;		// Force to check at startup
		private Version lastStableVersion;
				

		/// <summary>
		/// Executed on working thread
		/// </summary>
		private void CheckForNewVersion (bool forceShowResult)
		{
			string lastStableVersionInfo = GetLastStableVersionInfo();

			if (lastStableVersionInfo != null)
			{
				lastStableVersion = new Version (lastStableVersionInfo.Split ('\n')[0]);

				if ((lastStableVersion > AboutForm.Version) || 
					((lastStableVersion == AboutForm.Version) && (AboutForm.VersionStatus != "")))	// if alpha/beta version
				{
					SafeInvoke (new MethodInvoker (ShowNewVersion), null, Int32.MaxValue);
				}
				else if (forceShowResult)
				{
					SafeInvoke (new MethodInvoker (ShowNoNewVersion), null, Int32.MaxValue);
				}
			}
			else if (forceShowResult)
			{
				SafeInvoke (new MethodInvoker (ErrorCheckingForNewVersion), null, Int32.MaxValue);
			}
		}


		private string GetLastStableVersionInfo()
		{
			string version = ReadFromWeb ("http://svnnotifier.tigris.org/LastStableVersion.txt");

			if (version == null)	// Try to read from mirror site
			{
				version = ReadFromWeb  ("http://svnnotifier.googlecode.com/svn/www/LastStableVersion.txt");
			}

			return version;
		}


		private string ReadFromWeb (string url)
		{
			try
			{
				WebClient web = new WebClient();
				Stream s = web.OpenRead (url);
				string content = new StreamReader (s).ReadToEnd();

				if ((content.Length < 5) || (content.Length > 15))
					return null;	// Bad content

				return content;
			}
			catch
			{
				return null;		// Problem with web connection
			}
		}


		private void ShowNewVersion ()
		{
			if (MessageBox.Show (
				"New stable version of SVN Notifier is available - v" + lastStableVersion + "\n" + 
				"Do you want to go to the project home page?",
				"SVN Notifier", 
				MessageBoxButtons.OKCancel, MessageBoxIcon.Information) == DialogResult.OK)
				new AboutForm().ShowDialog ();
		}


		private void ShowNoNewVersion()
		{
			MessageBox.Show ("You are using latest version of SVN Notifier.",
				"SVN Notifier", MessageBoxButtons.OK, MessageBoxIcon.Information);
		}


		private void ErrorCheckingForNewVersion()
		{
			MessageBox.Show ("Can't check for new version!",
				"SVN Notifier", MessageBoxButtons.OK, MessageBoxIcon.Error);
		}

		#endregion 

		////////////////////////////////////////////////////////////////////////////////////
		
		private void FormStateChanged (bool _formIsActive)
		{
			formIsActive = _formIsActive;

			bool startTimer = statusUpdateTimer.Enabled;
			statusUpdateTimer.Stop ();

			if (startTimer) StartTimer();
		}


		private void StartTimer ()
		{
			int intervalMs = folders.FindNextStatusUpdateTimeMs (formIsActive);

			if ((intervalMs > 333) && (SvnTools.svnFolderProcesses.Count > 0))
				intervalMs = 333;	// Wait commit process(es) finish at least 3 times per second

			statusUpdateTimer.Interval = intervalMs == 0 ? 1 : intervalMs;
			statusUpdateTimer.Start ();
		}
		
		
		private void statusUpdateTimer_Elapsed (object sender, ElapsedEventArgs e)
		{
			BeginUpdateFolderStatuses ();

			if (WindowState == FormWindowState.Normal)
				Config.SaveMainFormSize (Width, Height);
		}


		private void BeginUpdateFolderStatuses () 
		{
			if (folders.Count > 0)
			{
				statusUpdateTimer.Stop();
				
				lock (this)
				{
					if (statusThread == null)
					{
						reupdateStatus = false;
						
						statusThread = new Thread (new ThreadStart (StatusUpdateThread_Run));
						statusThread.Start();
					}
					else
						reupdateStatus = true;
				}
			}
		}


		/// <summary>
		/// Executed on working thread
		/// </summary>
		private void StatusUpdateThread_Run()
		{
			try
			{
				while (!Created) Thread.Sleep (10);

				while (true)
				{
					SafeInvoke (new MethodInvoker (BeginUpdateListView));

					foreach (SvnFolder folder in (SvnFolderCollection) folders.Clone())
					{
						if (folder.Disable) continue;

						updateNotInProgress.WaitOne();

						if (forcedCheckForNewVersion)
						{
							forcedCheckForNewVersion = false;
							lastTimeOfCheckForNewVersion = DateTime.Now;
							SafeInvoke (new SetStatusBarTextMethod (SetStatusBarText), new object[] {"Checking for new version..."});
							CheckForNewVersion (true);
						}

						bool skipUpdateStatus = false;

						// Check commit and update processes for finishing
						for (int i = 0; i < SvnTools.svnFolderProcesses.Count; i++)
						{
							SvnFolderProcess sfp = (SvnFolderProcess) SvnTools.svnFolderProcesses[i];

							if (sfp.process.HasExited)
							{
								if (sfp.isUpdateCommand && SvnTools.HasUpdateErrors (sfp))
									SafeInvoke (new ShowUpdateErrorsMethod (ShowUpdateErrors), new object[] {sfp}, Int32.MaxValue);

								UpdateFolderStatus (sfp.folder);
								SvnTools.svnFolderProcesses.RemoveAt (i--);
							}
							else if ((folder.Path == sfp.folder.Path) && sfp.isUpdateCommand)
							{
								skipUpdateStatus = true;		// Because updating is still in progress
							}
						}

						while (forcedFolders.Count > 0)
							UpdateFolderStatus ((SvnFolder) forcedFolders.Dequeue());

						if ((folder.StatusTime + new TimeSpan (0, 0, folder.GetInterval (formIsActive)) <= DateTime.Now) && !skipUpdateStatus)
							UpdateFolderStatus (folder);
					}

					if (Config.CheckForNewVersion && (lastTimeOfCheckForNewVersion + new TimeSpan (3, 0, 0) < DateTime.Now))
					{
						lastTimeOfCheckForNewVersion = DateTime.Now;
						SafeInvoke (new SetStatusBarTextMethod (SetStatusBarText), new object[] {"Checking for new version..."});
						CheckForNewVersion (false);
					}

					lock (this)
					{
						if (!reupdateStatus)
						{
							statusThread = null;
							break;
						}
						else
							reupdateStatus = false;
					}
				}

				SafeInvoke (new MethodInvoker (EndUpdateListView));
			}
			catch (ThreadAbortException)
			{
				SvnTools.KillBackgroundProcess();
			}
			catch (Exception e)		// Otherwise it will just lost
			{
				ShowError ("Error on status thread: " + e.ToString());
				Application.Exit();
			}
		}


		/// <summary>
		/// Executed on working thread
		/// </summary>
		private void SafeInvoke (Delegate method)
		{
			SafeInvoke (method, null);
		}

		
		/// <summary>
		/// Executed on working thread
		/// </summary>
		private void SafeInvoke (Delegate method, object[] args)
		{
			SafeInvoke (method, args, 10000);
		}


		/// <summary>
		/// Executed on working thread
		/// </summary>
		private void SafeInvoke (Delegate method, object[] args, int timeoutMs)
		{
			// Begin/EndInvoke usage is workaround for "form.Invoke hungs sometimes" problem
			repeatInvoke = true;
			do
			{
				IAsyncResult ar;
				try
				{
					ar = BeginInvoke (new CheckedInvokeMethod (CheckedInvoke), new object[] {method, args});
				}
				catch	// Avoid exceptions for not yet created or disposed form
				{
					return;
				}

				if (ar.AsyncWaitHandle.WaitOne (timeoutMs, false))		// This timeout should be increased when debugging
				{
					try
					{
						EndInvoke(ar);
					}
					catch	// Avoid exceptions for not yet created or disposed form
					{
						return;
					}
				}
//				else
//					MessageBox.Show ("form.Invoke timeout!!! Repeat = " + repeatInvoke);		// Note: both "True" and "False" where observed
			} 
			while (repeatInvoke);
		}


		private void CheckedInvoke (Delegate method, object[] args)
		{
			method.DynamicInvoke (args);
			repeatInvoke = false;
		}


		/// <summary>
		/// Executed on working thread
		/// </summary>
		private void UpdateFolderStatus (SvnFolder folder)
		{
			SafeInvoke (new SetStatusBarTextMethod (SetStatusBarText), new object[] {"Checking '" + folder.Path + "'..."});
			DateTime statusTime = DateTime.Now;
			if (sessionEndInProgress) return;		// Need to avoid error on svn.exe invoking
			SvnFolderStatus status = SvnTools.GetSvnFolderStatus (folder);
			SafeInvoke (new UpdateListViewMethod (UpdateListView), new object[] {folder, status, statusTime});
		}


		private void BeginUpdateListView ()
		{
			newNonUpdatedFolders.Clear();
		}


		private void SetStatusBarText (string text)
		{
			statusBar.Panels[0].Text = text;
		}


		private void UpdateListView (SvnFolder folder, SvnFolderStatus folderStatus, DateTime statusTime)
		{
			int i = folders.IndexOf (folder);
			if (i < 0) return;

			if (statusTime < folder.StatusTime)
				return;

			if (folder.Status != folderStatus)
			{
				listViewFolders.Items[i].ImageIndex = GetFolderStatusImageIndex (folderStatus);

				folder.Status = folderStatus;

				if ((folderStatus == SvnFolderStatus.NeedUpdate) ||
					(folderStatus == SvnFolderStatus.NeedUpdate_Modified))
				{
					newNonUpdatedFolders.Add (folder);
					UpdateTray (true);
				}
				else
					UpdateTray (false);

				// Refresh buttons
				listViewFolders_SelectedIndexChanged (null, null);
			}
			else
				folder.Status = folderStatus;		// Update status time only
		}


		private void EndUpdateListView ()
		{
			statusBar.Panels[0].Text = null;

			// Reduce used memory
			GC.Collect ();
			EmptyWorkingSet (currentProcessHandle);
		
			StartTimer();
		}


		private void UpdateTray (bool newNonUpdatedFoldersChanged)
		{
			// Update tray ToolTip

			string trayText = Application.ProductName;

			foreach (SvnFolder folder in folders)
			{
				if ((folder.Status == SvnFolderStatus.NeedUpdate) ||
					(folder.Status == SvnFolderStatus.NeedUpdate_Modified))
				{
					if (trayText == Application.ProductName)
					{
						trayText += ". Update needed:";
					}
					
					if ((127 - 4) - trayText.Length > (1 + folder.VisiblePath.Length))
						trayText += "\n" + folder.VisiblePath;
					else
					{
						trayText += "\n...";
						break;
					}

				}
			}
			notifyIcon.Text = trayText;

			// Update tray icon

			Icon icon;
			if (folders.ContainsStatus (SvnFolderStatus.Error))
			{
				icon = trayIcon_Error;
			}	 
			else if ((folders.ContainsStatus (SvnFolderStatus.NeedUpdate)) ||
				(folders.ContainsStatus (SvnFolderStatus.NeedUpdate_Modified)))
			{
				icon = trayIcon_NeedUpdate;
			}	
			else if (folders.ContainsStatus (SvnFolderStatus.Unknown))
			{
				icon = trayIcon_Unknown;
			}
			else if ((folders.ContainsStatus (SvnFolderStatus.UpToDate)) ||
				(folders.ContainsStatus (SvnFolderStatus.UpToDate_Modified)))
			{
				icon = trayIcon_UpToDate;
			}
			else
				icon = trayIcon_Unknown;

			if (icon != Icon)
				Icon = notifyIcon.Icon = icon;


			// Update menu

			if (folders.ContainsStatus (SvnFolderStatus.NeedUpdate) ||
				folders.ContainsStatus (SvnFolderStatus.NeedUpdate_Modified))
			{
				menuItemUpdateAll.Enabled = true;
				menuItem_UpdateAll.Enabled = true;
			}
			else
			{
				menuItemUpdateAll.Enabled = false;
				menuItem_UpdateAll.Enabled = false;
			}

			if (newNonUpdatedFoldersChanged)
			{
				// Update tray ballon

				if (newNonUpdatedFolders.Count > 0)
				{
					string[] nonUpdatedFolders = new string [newNonUpdatedFolders.Count];
					for (int i = 0; i < newNonUpdatedFolders.Count; i++)
						nonUpdatedFolders[i] = listViewFolders.Items [folders.IndexOf (newNonUpdatedFolders[i])].Text;

					firstBalloonPath = nonUpdatedFolders[0];

					string balloonMessage = String.Join (Environment.NewLine, nonUpdatedFolders);
					notifyIcon.ShowBalloon ("Update needed", balloonMessage, NotifyIconEx.NotifyInfoFlags.Info, Config.ShowBallonInterval);
				}
				else
					notifyIcon.HideBallon();
			}
		}


		private void ShowUpdateErrors (SvnFolderProcess sfp)
		{
			new UpdateLogsForm (sfp.folder.Path, sfp.processOutput).ShowDialog (this);		
		}


		private void OnErrorAdded (string path, string error)
		{
			SafeInvoke (new UpdateErrorLogMethod (UpdateErrorLog), new object[] {path, error});
		}


		public void UpdateErrorLog (string path, string error)
		{
			if (statusBar.Panels[1].Icon == null)
				statusBar.Panels[1].Icon = errorLogIcon;

			if (path == null)
				path = "Checking for new version";

			string s = "[" + DateTime.Now.ToString () + "] " + Environment.NewLine +
				path + ":" + Environment.NewLine +
				error.Replace ("\n", Environment.NewLine) +
				Environment.NewLine + Environment.NewLine;

			errorLog[path] = s;
		}


		private void statusBar_PanelClick(object sender, StatusBarPanelClickEventArgs e)
		{
			if (e.Button != MouseButtons.Left)
				return;

			switch (statusBar.Panels.IndexOf(e.StatusBarPanel))
			{
				case 1 :
					if (errorLog.Count > 0)
						if (new ErrorLogForm (errorLog).ShowDialog (this) == DialogResult.Abort)
						{
							statusBar.Panels[1].Icon = null;
							errorLog.Clear();
						}
					break;
			}
		}


		//////////////////////////////////////////////////////////////////////////////
		
		private static int WM_QUERYENDSESSION	= 0x11;
		private static int WM_ENDSESSION		= 0x16;

		private static bool sessionEndInProgress = false;


		protected override void WndProc (ref Message m)
		{
			if (m.Msg == WM_QUERYENDSESSION)
				sessionEndInProgress = true;
			
			if ((m.Msg == WM_ENDSESSION) && ((int)m.WParam == 0))	// if "session end" was canceled (by some other reasons)
				sessionEndInProgress = false;
			
			base.WndProc (ref m);
		}
		
		//////////////////////////////////////////////////////////////////////////////
		
		[STAThread]
		private static void Main (string[] args)
		{
			try
			{
				if ((args.Length == 1) && (args[0] == "start"))		// Used to start application during install
				{
					ProcessStartInfo psi = new ProcessStartInfo (Application.ExecutablePath);
					psi.UseShellExecute = false;
					psi.WorkingDirectory = Path.GetDirectoryName (Application.ExecutablePath);
					Process.Start (psi);
					return;
				}

				string iniFileName = "SVN_Notifier.ini";
				if (File.Exists (iniFileName))
					Config.Init (iniFileName);
				else 
					Config.Init (Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), iniFileName));

				if (!Config.IsSettingsOK())
					if (new SettingsForm().ShowDialog() != DialogResult.OK)
						return;

				MainForm form = new MainForm();

				Thread.CurrentThread.Name = "Main";
				Application.ThreadException += new ThreadExceptionEventHandler (OnThreadException);
				Application.Run (form);

				lock (form)
				{
					if (statusThread != null) 
						statusThread.Abort();
				}
			}
			catch (Exception e)
			{
				ShowError (e.ToString());
			}
		}


		private static void OnThreadException (object sender, ThreadExceptionEventArgs t)
		{
			ShowError (t.Exception.ToString());
			Application.Exit();
		}


		private static void ShowError (string s)
		{
			MessageBox.Show (s, "SVN Notifier", MessageBoxButtons.OK, MessageBoxIcon.Error);
		}
	}
}
